package com.langangkj.home.cloud.generator;

import com.baomidou.mybatisplus.core.exceptions.MybatisPlusException;
import com.baomidou.mybatisplus.core.toolkit.StringPool;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.baomidou.mybatisplus.generator.AutoGenerator;
import com.baomidou.mybatisplus.generator.InjectionConfig;
import com.baomidou.mybatisplus.generator.config.*;
import com.baomidou.mybatisplus.generator.config.po.LikeTable;
import com.baomidou.mybatisplus.generator.config.po.TableInfo;
import com.baomidou.mybatisplus.generator.config.rules.DateType;
import com.baomidou.mybatisplus.generator.config.rules.NamingStrategy;
import com.baomidou.mybatisplus.generator.engine.FreemarkerTemplateEngine;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.langangkj.home.cloud.generator.properties.MybatisGeneratorProperties;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.CommandLineRunner;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.boot.context.properties.EnableConfigurationProperties;

import java.io.File;
import java.util.ArrayList;
import java.util.List;

/**
 * @author ZhouChuGang
 * @version 1.0
 * @project home-cloud
 * @date 2020/3/26 20:31
 * @Description mybatis plus 代码生成器
 */
@Slf4j
@EnableConfigurationProperties({MybatisGeneratorProperties.class})
@SpringBootApplication
public class MyBatisGenerator implements CommandLineRunner {

    @Autowired
    private MybatisGeneratorProperties mybatisGeneratorProperties;

    @Autowired
    private ObjectMapper objectMapper;

    public static void main(String[] args) {
        SpringApplication.run(MyBatisGenerator.class, args);
    }


    /**
     * 判断字符串地址 是否为绝对地址
     *
     * @param path
     * @return true 是绝对地址
     */
    private boolean pathIsAbsolute(String path) {
        return new File(path).isAbsolute();
    }

    /**
     * RUN THIS
     */
    private void generatorRun() {
        try {
            log.info("开始配置代码生成参数,属性配置文件值 {} ", objectMapper.writeValueAsString(mybatisGeneratorProperties));
        } catch (JsonProcessingException e) {
            e.printStackTrace();
        }
        // 代码生成器
        AutoGenerator mpg = new AutoGenerator();
        // 全局配置
        GlobalConfig gc = new GlobalConfig();
        gc.setDateType(DateType.ONLY_DATE);
        gc.setSwagger2(true);
        //判断保存的地址是否为绝对地址 如果是绝对地址 则直接赋值
        //如果为相对路径 则得到当前项目的地址  代码生成存放的路径
        String projectPath = System.getProperty("user.dir");
        String codePath = (pathIsAbsolute(mybatisGeneratorProperties.getBasePath()) ? "" : (projectPath + "/")) + mybatisGeneratorProperties.getBasePath();
        log.info("项目所在目录:{}  生成代码存放路径 : {}", projectPath, codePath);
        gc.setOutputDir(codePath);
        gc.setAuthor(mybatisGeneratorProperties.getAuthor());
        gc.setOpen(mybatisGeneratorProperties.isOpen());
        gc.setEnableCache(mybatisGeneratorProperties.isEnableCache());
        gc.setBaseResultMap(mybatisGeneratorProperties.isBaseResultMap());
        gc.setFileOverride(mybatisGeneratorProperties.isFileOverride());
        mpg.setGlobalConfig(gc);

        // 数据源配置
        DataSourceConfig dsc = new DataSourceConfig();
        dsc.setUrl(mybatisGeneratorProperties.getUrl());
        dsc.setDriverName(mybatisGeneratorProperties.getDriverName());
        dsc.setUsername(mybatisGeneratorProperties.getUserName());
        dsc.setPassword(mybatisGeneratorProperties.getPassWord());
        mpg.setDataSource(dsc);

        // 包配置
        PackageConfig pc = new PackageConfig();
        pc.setModuleName(mybatisGeneratorProperties.getModuleName());
        pc.setParent(mybatisGeneratorProperties.getParent());
        mpg.setPackageInfo(pc);
        // 自定义配置
        InjectionConfig cfg = new InjectionConfig() {
            //初始化
            @Override
            public void initMap() {
                // to do nothing
            }
        };
        List<FileOutConfig> focList = new ArrayList<>();
        // 自定义输入文件名称
        String varMapOutPath = mybatisGeneratorProperties.getMapperXmlOutputPath();
        log.info("生成的mapper.xml文件存在目录：{}", varMapOutPath);
        if (StringUtils.isBlank(varMapOutPath)) {
            log.warn("mapper存放目录为空，则修改为resource目录下，从存放代码的目录替换生成 {}", codePath);
            int index = codePath.indexOf("java");
            if (index < 0) {
                throw new MybatisPlusException("存放生成的代码路面没有找到java文件夹，替换失败，请配置mapper.xml存放目录");
            }
            String substring = codePath.substring(0, index);
            varMapOutPath = substring + "resources" + "/mapper";
        } else {
            varMapOutPath = projectPath + "/" + varMapOutPath;
        }
        final String mpperOutPath = varMapOutPath;
        log.info("存放mapper.xml的目录为 {} ", mpperOutPath);
        //这里用jar中自带的模板文件 生成 
        focList.add(new FileOutConfig("/templates/mapper.xml.ftl") {
            @Override
            public String outputFile(TableInfo tableInfo) {
                return mpperOutPath + "/" + tableInfo.getEntityName() + "Mapper" + StringPool.DOT_XML;
            }
        });
        cfg.setFileOutConfigList(focList);
        mpg.setCfg(cfg);
        //配置模板
        TemplateConfig templateConfig = new TemplateConfig();
        templateConfig.setXml(null);
        if (!mybatisGeneratorProperties.isGeneratorControllerCode()) {
            //不生成controller 层的代码l
            templateConfig.setController(null);
        }


        if (!mybatisGeneratorProperties.isGeneratorServiceCode()) {
            //不生成controller 层的代码l
            templateConfig.setServiceImpl(null);
            templateConfig.setService(null);
        }
        mpg.setTemplate(templateConfig);
        // 选择 freemarker 引擎需要指定如下加，注意 pom 依赖必须有！
        //这里必须要引入模板引擎  才能生成文件
        mpg.setTemplateEngine(new FreemarkerTemplateEngine());
        // 策略配置
        StrategyConfig strategy = new StrategyConfig();
        //使能lombok注解来写实体类
        strategy.setEntityLombokModel(true);
        //数据库表映射到实体的命名策略
        strategy.setNaming(NamingStrategy.underline_to_camel);
        //数据库表字段映射到实体的命名策略
        strategy.setColumnNaming(NamingStrategy.underline_to_camel);
        //是否存在所有实体的父类
        if (StringUtils.isNotBlank(mybatisGeneratorProperties.getSuperEntityClass())) {
            //配置实体类都要继承的父类
            strategy.setSuperEntityClass(mybatisGeneratorProperties.getSuperEntityClass());
            //自定义基础的Entity类，公共字段 这些字段在实体里不会存在，因为在父类已经存在了
            if (mybatisGeneratorProperties.getSuperEntityColumns() != null && mybatisGeneratorProperties.getSuperEntityColumns().length > 0) {
                strategy.setSuperEntityColumns(mybatisGeneratorProperties.getSuperEntityColumns());
            }
        }
        //是否配置通用的 mapper父类
        if (StringUtils.isNotBlank(mybatisGeneratorProperties.getSuperMapperClass())) {
            //配置controller类都要继承的父类
            strategy.setSuperMapperClass(mybatisGeneratorProperties.getSuperMapperClass());
        }
        //是否配置通用的 Iservice父类
        if (StringUtils.isNotBlank(mybatisGeneratorProperties.getSuperServiceClass())) {
            //配置controller类都要继承的父类
            strategy.setSuperServiceClass(mybatisGeneratorProperties.getSuperServiceClass());
        }

        //是否配置通用的 serviceImpl父类
        if (StringUtils.isNotBlank(mybatisGeneratorProperties.getSuperServiceImplClass())) {
            //配置controller类都要继承的父类
            strategy.setSuperServiceImplClass(mybatisGeneratorProperties.getSuperServiceImplClass());
        }

        //是否配置通用的 contorller父类
        if (StringUtils.isNotBlank(mybatisGeneratorProperties.getSuperControllerClass())) {
            //配置controller类都要继承的父类
            strategy.setSuperControllerClass(mybatisGeneratorProperties.getSuperControllerClass());
        }

        //如果生成controller 是否为rest 风格
        strategy.setRestControllerStyle(mybatisGeneratorProperties.isRestControllerStyle());

        //表前缀
        if (StringUtils.isNotBlank(mybatisGeneratorProperties.getTablePrefix())) {
            //表名的前缀 这样生成的实体会自动没有这个前缀
            strategy.setTablePrefix(mybatisGeneratorProperties.getTablePrefix());
        }

        //需要生成的表名 模糊查找
        if (StringUtils.isNotBlank(mybatisGeneratorProperties.getLikeTable())) {
            //需要生成的表名  包含即可
            strategy.setLikeTable(new LikeTable(mybatisGeneratorProperties.getLikeTable()));
        }

        //要排除的表名 模糊查找
        if (StringUtils.isNotBlank(mybatisGeneratorProperties.getNotLikeTable())) {
            //需要生成的表名  包含即可
            strategy.setNotLikeTable(new LikeTable(mybatisGeneratorProperties.getNotLikeTable()));
        }

        //需要生成的表名 列表
        if (mybatisGeneratorProperties.getInclude() != null && mybatisGeneratorProperties.getInclude().length > 0) {
            strategy.setInclude(mybatisGeneratorProperties.getInclude());
        }

        //需要排除的表名
        if (mybatisGeneratorProperties.getExclude() != null && mybatisGeneratorProperties.getExclude().length > 0) {
            strategy.setExclude(mybatisGeneratorProperties.getExclude());
        }
        //驼峰转连字符
        strategy.setControllerMappingHyphenStyle(false);
        if (StringUtils.isNotBlank(mybatisGeneratorProperties.getLogicDeleteFieldName())) {
            //逻辑删除字段名
            strategy.setLogicDeleteFieldName(mybatisGeneratorProperties.getLogicDeleteFieldName());
        }
        //生成实例时 属性是否加入注解
        strategy.setEntityTableFieldAnnotationEnable(mybatisGeneratorProperties.isEntityTableFieldAnnotationEnable());
        mpg.setStrategy(strategy);
        log.info("开始执行代码生成");
        mpg.execute();
    }

    @Override
    public void run(String... args) throws Exception {
        log.info("开始生成代码");
        //开始生成代码
        generatorRun();
        log.info("代码生成完成");
    }
}
